using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System;
using System.Runtime.InteropServices;

public class StewartPlatformGUI : MonoBehaviour
{
    public GUISkin guiSkin;

    // 窗口属性
    Rect windowRect;
    bool showRealtimeData = false;
    bool isRecording = false;
    
    // 布局缩放系数
    private float scaleFactor = 1.0f;
    
    // 原始窗口参考尺寸 - 用于计算比例
    private const float originalWidth = 400f;
    private const float originalHeight = 380f;

    // 杆长度数据和位姿数据
    private float[] rodLengths = new float[6] {351.8245358903903f, 353.2537476348852f, 353.17962646484375f, 
        353.7471923828125f, 353.7471923828125f, 353.7471923828125f };
    private Vector3 position = Vector3.zero;
    private Vector3 rotation = Vector3.zero;
    private int platformStatus = 0;

    // 相机控制参数
    private float moveSpeed = 5f;
    private float rotateSpeed = 100f;
    private float zoomSpeed = 500f;

    // UDP通信相关
    [Header("UDP Settings")] public string localIP = "192.168.3.23"; // 0.0.0.0表示监听所有网络接口
    public int localPort = 3002;
    public string targetIP = "192.168.3.23"; // 下位机IP
    public int targetPort = 3000; // 下位机端口

    private UdpClient udpClient;
    private IPEndPoint remoteEndPoint;
    private Thread udpThread;
    private bool isReceiving = false;
    private readonly object dataLock = new object();

    // 数据记录相关
    private List<string> recordedData = new List<string>();
    private string recordFilePath;

    // 协议相关常量
    private const uint HEADER_MARK = 0x66666666;
    private const uint TAIL_MARK = 0x88888888;
    
    
    // 弹窗相关
    private bool showCylinderInfo = false;
    private int selectedCylinder = -1;
    private Rect cylinderInfoRect;
    private float popupWidth;
    private float popupHeight;
    private Vector3 lastClickPosition;
    
    // 气缸游戏对象引用
    public GameObject[] cylinderObjects; // 可以通过Inspector指定，或者在Start中查找
    
    // 鼠标点击检测相关
    private Camera mainCamera;
    private Ray ray;
    private RaycastHit hit;
    
    

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    private struct ReceivedData
    {
        public uint header;
        public uint status;
        public float posX;
        public float posY;
        public float posZ;
        public float rotX;
        public float rotY;
        public float rotZ;
        public float rod1;
        public float rod2;
        public float rod3;
        public float rod4;
        public float rod5;
        public float rod6;
        public uint tail;
    }

    void Start()
    {
        // 计算自适应窗口大小
        CalculateWindowSize();

        // 初始化UDP接收
        InitializeUDP();

        // 确保数据目录存在
        string dataDir = Application.persistentDataPath + "/StewartPlatformData/";
        if (!Directory.Exists(dataDir))
        {
            Directory.CreateDirectory(dataDir);
        }
        
        mainCamera = Camera.main;
        
        // 初始化弹窗尺寸
        popupWidth = 125f;
        popupHeight = 60f;
        
        // 如果没有在Inspector中指定气缸对象，尝试在场景中查找
        if (cylinderObjects == null || cylinderObjects.Length == 0)
        {
            cylinderObjects = new GameObject[6];
            for (int i = 0; i < 6; i++)
            {
                cylinderObjects[i] = GameObject.Find($"cylinder{i+1}");
                if (cylinderObjects[i] == null)
                {
                    Debug.LogWarning($"找不到气缸对象 cylinder{i+1}");
                }
            }
        }
    }

    // 计算窗口大小，使高度占屏幕75%，保持原有宽高比
    void CalculateWindowSize()
    {
        // 计算目标高度为屏幕高度的75%
        float targetHeight = Screen.height * 0.75f;
        
        // 保持宽高比例计算宽度
        float targetWidth = targetHeight * (originalWidth / originalHeight);
        
        // 计算缩放因子，用于UI元素自适应
        scaleFactor = targetHeight / originalHeight;
        
        // 创建窗口矩形，并居中显示
        windowRect = new Rect(
            (Screen.width - targetWidth) / 2,
            (Screen.height - targetHeight) / 2,
            targetWidth,
            targetHeight
        );
        
    }

    void Update()
    {
        // 处理相机移动
        HandleCameraMovement();
        
        // 检测屏幕尺寸变化，并重新计算窗口大小
        if (Input.GetKeyDown(KeyCode.F11) || 
            (Screen.width != windowRect.width && Screen.height != windowRect.height))
        {
            CalculateWindowSize();
        }
        
        if (Input.GetMouseButtonDown(0))
        {
            // 如果窗口正在显示，并且点击在窗口之外，则关闭窗口
            if (showCylinderInfo && !cylinderInfoRect.Contains(Input.mousePosition))
            {
                showCylinderInfo = false;
            }
            
            // 发射射线检测点击的是否是气缸
            ray = mainCamera.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit))
            {
                // 检查点击的是否是气缸
                for (int i = 0; i < cylinderObjects.Length; i++)
                {
                    if (cylinderObjects[i] != null && hit.collider.gameObject == cylinderObjects[i])
                    {
                        // 如果当前窗口已显示且点击的是同一个气缸，则关闭窗口
                        if (showCylinderInfo && selectedCylinder == i)
                        {
                            showCylinderInfo = false;
                        }
                        else
                        {
                            // 显示新气缸的信息窗口
                            selectedCylinder = i;
                            showCylinderInfo = true;
                            lastClickPosition = Input.mousePosition;
                            
                            // 计算窗口位置，确保在屏幕内
                            float xPos = Mathf.Clamp(lastClickPosition.x, 10, Screen.width - popupWidth - 10);
                            float yPos = Mathf.Clamp(lastClickPosition.y, popupHeight + 10, Screen.height - 10);
                            cylinderInfoRect = new Rect(xPos, Screen.height - yPos, popupWidth, popupHeight);
                        }
                        break;
                    }
                }
            }
        }
    }

    void OnGUI()
{
    GUI.skin = guiSkin;

    // 使窗口可拖动
    windowRect = GUI.Window(0, windowRect, DoMyWindow, "多模态六自由度机器人数字孪生系统");
    if (showCylinderInfo && selectedCylinder >= 0 && selectedCylinder < rodLengths.Length)
    {
        // 创建缩放后的样式
        GUIStyle scaledWindowStyle = new GUIStyle(GUI.skin.window);
        scaledWindowStyle.fontSize = Mathf.RoundToInt(GUI.skin.window.fontSize * scaleFactor);
        
        GUIStyle scaledValueStyle = new GUIStyle(GUI.skin.label);
        scaledValueStyle.fontSize = Mathf.RoundToInt(GUI.skin.label.fontSize * 1.2f * scaleFactor);
        scaledValueStyle.alignment = TextAnchor.MiddleCenter;
        scaledValueStyle.fontStyle = FontStyle.Bold;
        
        // 绘制气缸信息窗口
        cylinderInfoRect = GUI.Window(100, cylinderInfoRect, (id) => {
            // 信息布局 - 调整起始位置，因为不再需要杆名称行
            float yPos = 25 * scaleFactor;
            
            // 直接显示当前长度 (大号字体，居中)
            GUI.Label(new Rect(10, yPos, cylinderInfoRect.width - 20, 40 * scaleFactor), 
                $"{rodLengths[selectedCylinder]:F2} mm", scaledValueStyle);
            
            // 允许窗口拖动
            GUI.DragWindow();
        }, $"杆{selectedCylinder + 1}长度", scaledWindowStyle);
    }
}


    void DoMyWindow(int windowID)
{
    // 标题已在窗口创建时设置，这里从正文内容开始
    float yPosition = 30 * scaleFactor;
    float buttonHeight = 30 * scaleFactor;
    float labelHeight = 25 * scaleFactor;
    float spacing = 10 * scaleFactor;

    // 创建缩放后的文本样式
    GUIStyle scaledLabelStyle = new GUIStyle(GUI.skin.label);
    scaledLabelStyle.fontSize = Mathf.RoundToInt(GUI.skin.label.fontSize * scaleFactor);
    
    // 创建缩放后的按钮样式
    GUIStyle scaledButtonStyle = new GUIStyle(GUI.skin.button);
    scaledButtonStyle.fontSize = Mathf.RoundToInt(GUI.skin.button.fontSize * scaleFactor);
    
    // 创建缩放后的框样式
    GUIStyle scaledBoxStyle = new GUIStyle(GUI.skin.box);
    scaledBoxStyle.fontSize = Mathf.RoundToInt(GUI.skin.box.fontSize * scaleFactor);

    // 欢迎文本
   GUI.Label(new Rect(10 * scaleFactor, yPosition, windowRect.width - 20 * scaleFactor, labelHeight), 
    System.DateTime.Now.ToString("yyyy年MM月dd日 HH:mm:ss"), scaledLabelStyle);
    yPosition += labelHeight + spacing;

    // 三个主按钮
    float buttonWidth = (windowRect.width - 40 * scaleFactor) / 3;
    
    if (GUI.Button(new Rect(10 * scaleFactor, yPosition, buttonWidth, buttonHeight), 
        showRealtimeData ? "关闭实时数据" : "实时数据", scaledButtonStyle))
    {
        showRealtimeData = !showRealtimeData;
    }

    if (GUI.Button(new Rect(20 * scaleFactor + buttonWidth, yPosition, buttonWidth, buttonHeight), 
        isRecording ? "停止记录" : "记录数据", scaledButtonStyle))
    {
        isRecording = !isRecording;
        if (isRecording)
        {
            StartRecording();
        }
        else
        {
            StopRecording();
        }
    }

    if (GUI.Button(new Rect(30 * scaleFactor + buttonWidth * 2, yPosition, buttonWidth, buttonHeight), 
        "历史数据", scaledButtonStyle))
    {
        ShowHistoryData();
    }

    yPosition += buttonHeight + spacing;

    // 显示实时数据
    if (showRealtimeData)
    {
        float boxHeight = windowRect.height - yPosition - 10 * scaleFactor;
        GUI.Box(new Rect(10 * scaleFactor, yPosition, windowRect.width - 20 * scaleFactor, boxHeight), 
            "实时数据", scaledBoxStyle);
        yPosition += 30 * scaleFactor;

        lock (dataLock)
        {
            float elementHeight = 20 * scaleFactor;
            float leftMargin = 20 * scaleFactor;
            
            // 显示状态
            GUI.Label(new Rect(leftMargin, yPosition, windowRect.width - leftMargin * 2, elementHeight), 
                $"平台状态: {platformStatus}", scaledLabelStyle);
            yPosition += elementHeight + spacing / 2;

            // 显示杆长度
            for (int i = 0; i < 6; i++)
            {
                GUI.Label(new Rect(leftMargin, yPosition, windowRect.width - leftMargin * 2, elementHeight), 
                    $"杆{i + 1}: {rodLengths[i]:F2} mm", scaledLabelStyle);
                yPosition += elementHeight + spacing / 2;
            }

            // 显示位置和旋转
            GUI.Label(new Rect(leftMargin, yPosition, windowRect.width - leftMargin * 2, elementHeight),
                $"位置: X={position.x:F2}, Y={position.y:F2}, Z={position.z:F2}", scaledLabelStyle);
            yPosition += elementHeight + spacing / 2;
            
            GUI.Label(new Rect(leftMargin, yPosition, windowRect.width - leftMargin * 2, elementHeight),
                $"旋转: X={rotation.x:F2}°, Y={rotation.y:F2}°, Z={rotation.z:F2}°", scaledLabelStyle);
        }
    }

    // 允许窗口拖动
    // 允许窗口拖动 - 使用足够大的区域确保整个窗口顶部可以拖动
    //GUI.DragWindow(new Rect(0, 0, 10000, 30 * scaleFactor));
	GUI.DragWindow (new Rect (0,0,10000,10000));
}



    void InitializeUDP()
    {
        try
        {
            // 创建UDP客户端并绑定到指定的IP和端口
            udpClient = new UdpClient();

            // 如果指定了特定的本地IP，则绑定到该IP
            if (localIP != "0.0.0.0")
            {
                IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(localIP), localPort);
                udpClient.Client.Bind(localEndPoint);
            }
            else
            {
                // 否则绑定到所有网络接口
                IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, localPort);
                udpClient.Client.Bind(localEndPoint);
            }

            remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);

            isReceiving = true;
            udpThread = new Thread(ReceiveData);
            udpThread.IsBackground = true;
            udpThread.Start();

            Debug.Log($"UDP接收器已初始化，监听 {(localIP == "0.0.0.0" ? "所有接口" : localIP)}:{localPort}");
        }
        catch (Exception e)
        {
            Debug.LogError($"UDP初始化失败: {e.Message}");
        }
    }

void ReceiveData()
{
    while (isReceiving)
    {
        try
        {
            byte[] data = udpClient.Receive(ref remoteEndPoint);

            // 检查是否来自目标IP
            if (targetIP != "0.0.0.0" && remoteEndPoint.Address.ToString() != targetIP)
            {
                Debug.Log($"收到来自非目标IP的数据: {remoteEndPoint.Address}，已忽略");
                continue;
            }

            Debug.Log($"收到数据，长度: {data.Length} 字节，来自: {remoteEndPoint.Address}:{remoteEndPoint.Port}");

            // 获取ReceivedData结构体的大小
            int expectedSize = Marshal.SizeOf(typeof(ReceivedData));
            
            // 检查接收到的数据是否至少包含足够的字节来解析一个结构体
            if (data.Length >= expectedSize)
            {
                // 解析大端序数据
                try
                {
                    ReceivedData receivedData = ParseBigEndianData(data);
                    
                    // 验证头尾标记
                    if (receivedData.header == HEADER_MARK && receivedData.tail == TAIL_MARK)
                    {
                        Debug.Log($"解析成功: 状态={receivedData.status}, X={receivedData.posX}, Y={receivedData.posY}, Z={receivedData.posZ},\n" +
                                  $" 杆1={receivedData.rod1}, 杆2={receivedData.rod2}, 杆3={receivedData.rod3}, 杆4={receivedData.rod4}, 杆5={receivedData.rod5}, 杆6={receivedData.rod6}");
                        ProcessReceivedData(receivedData);
                    }
                    else
                    {
                        Debug.LogWarning($"收到无效数据包，头尾标记不匹配: 头部={receivedData.header:X8}, 尾部={receivedData.tail:X8}");
                    }
                }
                catch (Exception parseEx)
                {
                    Debug.LogError($"解析数据结构时出错: {parseEx.Message}");
                }
            }
            else
            {
                Debug.LogWarning($"收到数据长度 {data.Length} 小于预期结构体大小 {expectedSize}，无法解析");
            }
        }
        catch (SocketException e)
        {
            // 处理常见的网络错误
            if (isReceiving)
            {
                Debug.LogError($"UDP接收网络错误: {e.Message}, 错误码: {e.ErrorCode}");
                
                // 对于某些可恢复的错误，可以尝试重新初始化UDP
                if (e.ErrorCode == 10054) // 连接重置
                {
                    Debug.Log("尝试重新初始化UDP连接...");
                    try
                    {
                        udpClient.Close();
                        InitializeUDP();
                    }
                    catch (Exception reinitEx)
                    {
                        Debug.LogError($"重新初始化UDP失败: {reinitEx.Message}");
                    }
                }
            }
        }
        catch (Exception e)
        {
            if (isReceiving)
            {
                Debug.LogError($"UDP接收其他错误: {e.Message}");
                Debug.LogException(e); // 打印完整堆栈以便调试
            }
        }
    }
}

// 解析大端序数据
private ReceivedData ParseBigEndianData(byte[] data)
{
    ReceivedData result = new ReceivedData();
    
    int offset = 0;
    
    // 1. 读取头部标记 (uint - 4字节)
    result.header = SwapEndianUInt32(BitConverter.ToUInt32(data, offset));
    offset += 4;
    
    // 2. 读取状态 (uint - 4字节)
    result.status = SwapEndianUInt32(BitConverter.ToUInt32(data, offset));
    offset += 4;
    
    // 3-5. 读取位置 (3个float - 12字节)
    result.posX = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.posY = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.posZ = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    
    // 6-8. 读取旋转 (3个float - 12字节)
    result.rotX = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.rotY = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.rotZ = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    
    // 9-14. 读取六个杆长 (6个float - 24字节)
    result.rod1 = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.rod2 = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.rod3 = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.rod4 = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.rod5 = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    result.rod6 = SwapEndianFloat(BitConverter.ToSingle(data, offset));
    offset += 4;
    
    // 15. 读取尾部标记 (uint - 4字节)
    result.tail = SwapEndianUInt32(BitConverter.ToUInt32(data, offset));
    
    return result;
}

// 交换UInt32的字节序（大端到小端）
private uint SwapEndianUInt32(uint value)
{
    return ((value & 0x000000FF) << 24) |
           ((value & 0x0000FF00) << 8) |
           ((value & 0x00FF0000) >> 8) |
           ((value & 0xFF000000) >> 24);
}

// 交换Float的字节序（大端到小端）- 不使用unsafe
private float SwapEndianFloat(float value)
{
    byte[] bytes = BitConverter.GetBytes(value);
    Array.Reverse(bytes);
    return BitConverter.ToSingle(bytes, 0);
}

// 调试用：打印字节内容
private void DebugPrintBytes(byte[] data, int maxBytes = 64)
{
    int length = Mathf.Min(data.Length, maxBytes);
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    sb.Append("原始字节内容: ");
    
    for (int i = 0; i < length; i++)
    {
        sb.Append(data[i].ToString("X2") + " ");
        if ((i + 1) % 4 == 0) sb.Append("| ");
        if ((i + 1) % 16 == 0 && i < length - 1) sb.Append("");
    }
    
    Debug.Log(sb.ToString());
}


    void ProcessReceivedData(ReceivedData data)
    {
        lock (dataLock)
        {
            // 更新状态
            platformStatus = (int)data.status;

            // 更新位置和旋转 (旋转已转换为角度)
            position = new Vector3(data.posX, data.posY, data.posZ);
            rotation = new Vector3(data.rotX, data.rotY, data.rotZ);

            // 更新杆长度
            rodLengths[0] = data.rod1;
            rodLengths[1] = data.rod2;
            rodLengths[2] = data.rod3;
            rodLengths[3] = data.rod4;
            rodLengths[4] = data.rod5;
            rodLengths[5] = data.rod6;

            // 如果正在记录，则记录当前数据
            if (isRecording)
            {
                string dataLine =
                    $"{Time.time},{platformStatus},{position.x},{position.y},{position.z},{rotation.x},{rotation.y},{rotation.z},{string.Join(",", rodLengths)}";
                recordedData.Add(dataLine);
            }
        }
    }

    // 辅助方法：将字节数组转换为结构体
    T ByteArrayToStructure<T>(byte[] bytes) where T : struct
    {
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        try
        {
            return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        }
        finally
        {
            handle.Free();
        }
    }

    void StartRecording()
    {
        Debug.Log("开始记录数据");
        recordedData.Clear();

        // 添加CSV头部
        recordedData.Add("Time,Status,PosX,PosY,PosZ,RotX,RotY,RotZ,Rod1,Rod2,Rod3,Rod4,Rod5,Rod6");

        string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
        recordFilePath = Application.persistentDataPath + $"/StewartPlatformData/StewartData_{timestamp}.csv";
    }

    void StopRecording()
    {
        Debug.Log("停止记录数据");

        try
        {
            // 将记录的数据写入文件
            File.WriteAllLines(recordFilePath, recordedData.ToArray());
            Debug.Log($"数据已保存到: {recordFilePath}");
        }
        catch (Exception e)
        {
            Debug.LogError($"保存数据文件失败: {e.Message}");
        }
    }

    void ShowHistoryData()
    {
        Debug.Log("显示历史数据");

        string dataDir = Application.persistentDataPath + "/StewartPlatformData/";
        if (Directory.Exists(dataDir))
        {
            string[] files = Directory.GetFiles(dataDir, "*.csv");
            if (files.Length > 0)
            {
                // 打印出所有可用的数据文件
                Debug.Log("可用的数据文件:");
                foreach (string file in files)
                {
                    Debug.Log(Path.GetFileName(file));
                }
            }
            else
            {
                Debug.Log("没有找到数据文件");
            }
        }
    }

    // 相机控制
    void HandleCameraMovement()
    {
        // 平移
        float horizontal = Input.GetAxis("Horizontal") * moveSpeed * Time.deltaTime;
        float vertical = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;

        transform.Translate(horizontal, 0, vertical);

        // 旋转 (鼠标右键)
        if (Input.GetMouseButton(1))
        {
            float mouseX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
            float mouseY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;

            transform.Rotate(Vector3.up, mouseX);
            transform.Rotate(Vector3.right, -mouseY);
        }

        // 缩放 (鼠标滚轮)
        float scroll = Input.GetAxis("Mouse ScrollWheel");
        transform.Translate(0, 0, scroll * zoomSpeed * Time.deltaTime);
    }

    void OnDestroy()
    {
        // 停止UDP接收
        isReceiving = false;

        // 关闭UDP客户端
        if (udpClient != null)
        {
            udpClient.Close();
            udpClient = null;
        }

        // 等待接收线程结束
        if (udpThread != null && udpThread.IsAlive)
        {
            udpThread.Join(1000); // 最多等待1秒
        }

        // 如果正在记录，保存数据
        if (isRecording)
        {
            StopRecording();
        }
    }
}
